//
//  UIntStorageFormatter.c
//  EZFoundation
//
//  Created by ellzu gu on 2021/8/2.
//

#include "UIntStorageFormatter.h"
#include <arpa/inet.h> 

inline uint16_t UIntStorageFormatter_swap16(uint16_t num, uint8_t swapEndian) {
    return swapEndian == 0 ? num : htons(num);
//    return swapEndian == 0 ? num : (0x00FF & (num >> 8)) | (0xFF00 & (num << 8));
}

inline uint32_t UIntStorageFormatter_swap32(uint32_t num, uint8_t swapEndian) {
    return swapEndian == 0 ? num : htonl(num);
//    return swapEndian == 0 ? num : (0x000000FF & (num >> 24)) | (0x0000FF00 & (num >> 8)) | (0x00FF0000 & (num << 8)) | (0xFF000000 & (num << 24));
}

inline uint64_t UIntStorageFormatter_swap64(uint64_t num, uint8_t swapEndian) {
    return swapEndian == 0 ? num : htonll(num);
//    return swapEndian == 0 ? num : (0x00000000000000FF & (num >> 56))
//    | (0x000000000000FF00 & (num >> 40))
//    | (0x0000000000FF0000 & (num >> 24))
//    | (0x00000000FF000000 & (num >> 8))
//    | (0x000000FF00000000 & (num << 8))
//    | (0x0000FF0000000000 & (num << 24))
//    | (0x00FF000000000000 & (num << 40))
//    | (0xFF00000000000000 & (num << 56));
}

static uint8_t UIntStorageFormatter_readUInt8(const UIntStorageFormatter* formatter, const UIntStorage* storage, uint32_t offset) {
    return *((uint8_t*)(storage->data + offset));
}

static void UIntStorageFormatter_replaceUInt8(const UIntStorageFormatter* formatter, const UIntStorage* storage, uint32_t offset, uint8_t value) {
    *((uint8_t *)(storage->data + offset)) = value;
}

static uint16_t UIntStorageFormatter_readUInt16(const UIntStorageFormatter* formatter, const UIntStorage* storage, uint32_t offset) {
    return UIntStorageFormatter_swap16(*((uint16_t *)(storage->data + offset)), formatter->swapEndian);
}

static void UIntStorageFormatter_replaceUInt16(const UIntStorageFormatter* formatter, const UIntStorage* storage, uint32_t offset, uint16_t value) {
    *((uint16_t *)(storage->data + offset)) = UIntStorageFormatter_swap16(value, formatter->swapEndian);
}

static uint32_t UIntStorageFormatter_readUInt32(const UIntStorageFormatter* formatter, const UIntStorage* storage, uint32_t offset) {
    return UIntStorageFormatter_swap32(*((uint32_t *)(storage->data + offset)), formatter->swapEndian);
}

static void UIntStorageFormatter_replaceUInt32(const UIntStorageFormatter* formatter, const UIntStorage* storage, uint32_t offset, uint32_t value) {
    *((uint32_t *)(storage->data + offset)) = UIntStorageFormatter_swap32(value, formatter->swapEndian);
}

static uint64_t UIntStorageFormatter_readUInt64(const UIntStorageFormatter* formatter, const UIntStorage* storage, uint32_t offset) {
    return UIntStorageFormatter_swap64(*((uint64_t *)(storage->data + offset)), formatter->swapEndian);
}

static void UIntStorageFormatter_replaceUInt64(const UIntStorageFormatter* formatter, const UIntStorage* storage, uint32_t offset, uint64_t value) {
    *((uint64_t *)(storage->data + offset)) = UIntStorageFormatter_swap64(value, formatter->swapEndian);
}

static uint8_t UIntStorageFormatter_readBit(const UIntStorageFormatter* formatter, const UIntStorage* storage, uint32_t offset, uint32_t bitOffset) {
    uint8_t temp = UIntStorageFormatter_readUInt8(formatter, storage, offset);
    return (temp >> bitOffset) & 0x01;
}

static void UIntStorageFormatter_replaceBit(const UIntStorageFormatter* formatter, const UIntStorage* storage, uint32_t offset, uint32_t bitOffset, uint8_t value) {
    uint8_t temp = UIntStorageFormatter_readUInt8(formatter, storage, offset);
    uint8_t flag = 0x01 << bitOffset;
    *((uint8_t *)(storage->data + offset)) = (value == 0 ? temp & ~flag : temp | flag);
}

UIntStorage MakeUIntStorage(const void *data) {
    struct _UIntStorage storage = {
        .data = data
    };
    return storage;
}

UIntStorageFormatter MakeUIntStorageFormatter(uint8_t swapEndian) {
    struct _UIntStorageFormatter formatter = {
        .swapEndian = swapEndian,
        .readBit = UIntStorageFormatter_readBit,
        .replaceBit = UIntStorageFormatter_replaceBit,
        .readUInt8 =  UIntStorageFormatter_readUInt8,
        .replaceUInt8 = UIntStorageFormatter_replaceUInt8,
        .readUInt16 = UIntStorageFormatter_readUInt16,
        .replaceUInt16 = UIntStorageFormatter_replaceUInt16,
        .readUInt32 = UIntStorageFormatter_readUInt32,
        .replaceUInt32 = UIntStorageFormatter_replaceUInt32,
        .readUInt64 = UIntStorageFormatter_readUInt64,
        .replaceUInt64 = UIntStorageFormatter_replaceUInt64
    };
    return  formatter;
}
